import { Object3D, Ray, Vector3 } from "three";
import { MathUtils } from "three/src/math/MathUtils";
import { App } from "../../application";
import Helper from "../../utils/Helper";
import MeshUtil from "./MeshUtil";

export default class CameraUtils {
    private intersectObjsWithEye: Array<Object3D> = []; //和相机做碰撞检测的物体数组
    public isCollisionEye: boolean = false; //相机是否和场景中的mesh发生碰撞
    private static instance: CameraUtils;
    private static cameranCheckBoxTag = 'checkCameranBox';

    private constructor() {

    }

    public static getInstance() {
        if (!this.instance) {
            this.instance = new CameraUtils();
        }
        return this.instance;
    }

    /**
     * 检测相机是否和intersectObjsWithEye数组中的mesh发生碰撞
     * @param oldCameraPosition 相机旧的位置
     * @param oldCamraTarget 相机旧的看向的位置
     * @param newCameraPosition 相机新的位置
     * @param newCameraTarget 相机新的看向的位置
     * @param isDrag 是否拖拽
     * @returns 返回的对象类型：{eyePoint, eyeTarget, isCollisionEye}。eyePoint：相机新的位置；eyeTarget：相机新的看向的位置；isCollisionEye：相机是否和intersectObjsWithEye数组中的mesh发生碰撞
     */
    public adjustCameraPosition(oldCameraPosition, oldCamraTarget, newCameraPosition, newCameraTarget) {
        let intesectPointArray = this.getIntersectArray(oldCameraPosition, newCameraPosition);
        let minDistance = oldCameraPosition.distanceTo(newCameraPosition);

        let cameraNear = App.getInstance().three.camera.near;
      
        if(intesectPointArray.length > 0 && intesectPointArray[0].distanceTo(oldCameraPosition) <= minDistance + cameraNear) {
            let intersectPoint = intesectPointArray[0];
            let directionVector = new Vector3(oldCameraPosition.x - newCameraPosition.x, oldCameraPosition.y - newCameraPosition.y, oldCameraPosition.z - newCameraPosition.z);
            directionVector.normalize();
            directionVector.multiplyScalar(cameraNear + cameraNear);

            let newEyePoint = new Vector3(intersectPoint.x, intersectPoint.y, intersectPoint.z).add(directionVector);
            this.isCollisionEye = true;
            return {eyePoint: newEyePoint, eyeTarget: newCameraTarget, isCollisionEye: true}; //; //

            // this.isCollisionEye = true;
            // return { eyePoint: oldCameraPosition, eyeTarget: oldCamraTarget, isCollisionEye: true };
        }
        this.isCollisionEye = false;
        return { eyePoint: newCameraPosition, eyeTarget: newCameraTarget, isCollisionEye: false }; //;
    }

    private getIntersectArray(oldCameraPosition, newCameraPosition){
        let rayDirection = newCameraPosition.clone().sub(oldCameraPosition).normalize();
        let ray: Ray = new Ray(oldCameraPosition, rayDirection);
        let intesectPointArray = [];
        for(let i=0; i<this.intersectObjsWithEye.length; i++) {
            let obj = this.intersectObjsWithEye[i];
            Helper.traverseObject(obj, function(child){
                if (child.isMesh){
                    let boundingBox = child[CameraUtils.cameranCheckBoxTag];
                    if(!boundingBox){
                        boundingBox = MeshUtil.getMeshBoundingBox(child); //获取mesh的包围盒
                        child[CameraUtils.cameranCheckBoxTag] = boundingBox;
                    }
                    let intersectPoint = new Vector3();
                    ray.intersectBox(boundingBox, intersectPoint);

                    if(intersectPoint.length() > 0){
                        intesectPointArray.push(intersectPoint);
                    }
                   
                    return false;
                }
                return true;
            });
        }

        if(intesectPointArray.length > 0){
            intesectPointArray.sort(function(a, b){
                var distanceToA = a.distanceTo(oldCameraPosition);
                var distanceToB = b.distanceTo(oldCameraPosition);
              
                // 根据距离排序
                return distanceToA - distanceToB;
            })
        }
        return intesectPointArray;
    }

    private static computeCameraNear(closestPoint: Vector3) {
        let cameraNear = closestPoint.distanceTo(App.getInstance().three.camera.position);
        cameraNear = cameraNear / 10;
        App.getInstance().three.camera.near = cameraNear;
        console.log(cameraNear);
        App.getInstance().three.camera.updateProjectionMatrix();
    }

    /**
     * 添加和相机做碰撞检测的物体
     * @param obj 
     */
    public addIntersectObjWithEye(obj: Object3D) {
        this.intersectObjsWithEye.push(obj);
    }

    /**
     * 移除和相机做碰撞检测的物体
     * @param obj 
     */
    public removeIntersectObjWithEye(obj: Object3D) {
        let index = this.intersectObjsWithEye.indexOf(obj);
        if (index > -1) {
            this.intersectObjsWithEye.splice(index, 1);
        }
    }

    /**
     * 得到相机水平的视场角
     */
    public getHorizontalFov() {
        let app = App.getInstance();
        let verticalFov = app.three.camera.fov;
        let aspect = app.three.camera.aspect;

        // 将垂直视场角从度转换为弧度
        var fovVerticalRad = MathUtils.degToRad(verticalFov);
        var horizontalFovRad = 2 * Math.atan(Math.tan(fovVerticalRad / 2) * aspect);
        let horizontalFov = MathUtils.radToDeg(horizontalFovRad);
        return horizontalFov;
    }
}